package com.dai.rpc.netty.handler;

import com.dai.rpc.constant.CompressTypeEnum;
import com.dai.rpc.constant.MessageTypeEnum;
import com.dai.rpc.constant.MyRpcConstants;
import com.dai.rpc.constant.SerializationTypeEnum;
import com.dai.rpc.exceptions.MyRpcException;
import com.dai.rpc.factory.SingletonFactory;
import com.dai.rpc.message.RpcMessage;
import com.dai.rpc.message.RpcResponse;
import com.dai.rpc.netty.client.UnprocessedRequests;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyNettyClientHandler extends ChannelInboundHandlerAdapter {

    private UnprocessedRequests unprocessedRequests;

    public MyNettyClientHandler() {
        this.unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 从future对象获取到服务器返回的结果
        try{
            if(msg instanceof RpcMessage){
                RpcMessage message = (RpcMessage) msg;
                if(message.getMessageType() == MessageTypeEnum.RESPONSE.getCode()){
                    RpcResponse response = (RpcResponse)message.getData();
                    // 把结果放入队列
                    unprocessedRequests.complete(response);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new MyRpcException("数据格式异常...");
        }finally {
            // netty自带的包进行释放
            ReferenceCountUtil.release(msg);
        }

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

        if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent) evt;
            if(event.state() == IdleState.WRITER_IDLE){
                // 发送心跳包到服务端
                RpcMessage build = RpcMessage.builder()
                        .codec(SerializationTypeEnum.PROTO_STUFF.getCode())
                        .compress(CompressTypeEnum.GZIP.getCode())
                        .messageType(MessageTypeEnum.HEARTBEAT_PING.getCode())
                        .data(MyRpcConstants.RPC_PING)
                        .build();
                log.info("客户端发送心跳包....");
                ctx.writeAndFlush(build).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        }else{
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("通道连接状态正常....");
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("服务端关闭连接...");
        // 消除缓存

        // 标识channel关闭
        ctx.fireChannelInactive();
    }
}
